package cc.rengu.igas.share.core.service.trans;

import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.common.enums.FeeTypeEnum;
import cc.rengu.igas.share.common.enums.RespCodeEnum;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.igas.share.core.service.base.NoticeService;
import cc.rengu.igas.share.facade.request.WechatPayResultNoticeRequest;
import cc.rengu.igas.share.facade.response.WechatPayResultNoticeResponse;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.realize.OrderService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.TransCustomImpl;
import cc.rengu.oltp.service.realize.impl.OrderServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/*
 *Create by wangcheng on 2021-09-30
 * 微信支付异步通知结果处理
 */

public class WchatPayResultNoticeService extends NoticeService implements TransCustomImpl {

    @Override
    protected Object bizBeforeCust() throws Exception {
        WechatPayResultNoticeRequest wechatPayResultNoticeRequest = new WechatPayResultNoticeRequest();
        ConvertUtil.convertOutput(wechatPayResultNoticeRequest);
        return wechatPayResultNoticeRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        WechatPayResultNoticeRequest wechatPayResultNoticeRequest = (WechatPayResultNoticeRequest) request;
        WechatPayResultNoticeResponse wechatPayResultNoticeResponse = new WechatPayResultNoticeResponse();
        wechatPayResultNoticeResponse.setHeader(wechatPayResultNoticeRequest.getHeader());
        BizResponse bizResponse = new BizResponse();
        String instId = wechatPayResultNoticeRequest.getHeader().getInstId();
        String orderId = wechatPayResultNoticeRequest.getOrderId();

        /* 获取通知交易的原交易订单信息 */
        OrderService orderService = new OrderServiceImpl();
        OrderInfo orderInfo = orderService.selectOrderInfoBySysSeqNum(instId, orderId);
        if (null == orderInfo) {
            rglog.error("机构<{}>没有对应的银联订单号<{}>信息", instId, orderId);
            throw new BizException(RespCodeEnum.ORDER_NOT_EXIST.getRespCode(), RespCodeEnum.ORDER_NOT_EXIST.getRespDesc());
        }
        UserOrderInfo userOrderInfo = orderInfo.getUserOrderInfo();
        List<MchntOrderInfo> mchntOrderInfoList = orderInfo.getMchntOrderInfoList();
        List<PayOrderInfo> payOrderInfoList = orderInfo.getPayOrderInfoList();
        Optional<PayOrderInfo> payOrderInfoOpt = payOrderInfoList.stream().filter(item -> item.getMsgDstId().equals(ChannelEnum.UPWX.getChannelType()) ||
                item.getMsgDstId().equals(ChannelEnum.NUWX.getChannelType()) || item.getMsgDstId().equals(ChannelEnum.WXZF.getChannelType())).findFirst();
        if (!payOrderInfoOpt.isPresent()) {
            rglog.error("机构<{}>没有对应的银联订单号<{}>信息", instId, orderId);
            throw new BizException(RespCodeEnum.ORDER_NOT_EXIST.getRespCode(), RespCodeEnum.ORDER_NOT_EXIST.getRespDesc());
        }
        PayOrderInfo payOrderInfo = payOrderInfoList.get(0);
        if (TransStatusEnum.TRANS_SUCC.getStatus().equals(payOrderInfo.getTransStatus()) &&
                (BizStatusEnum.FINISH.getStatus().equals(payOrderInfo.getBizStatus()) ||
                        BizStatusEnum.REFUND.getStatus().equals(payOrderInfo.getBizStatus()) ||
                        BizStatusEnum.PART_REFUND.getStatus().equals(payOrderInfo.getBizStatus()) ||
                        BizStatusEnum.CONFIRM.getStatus().equals(payOrderInfo.getBizStatus()))) {
            rglog.debug("订单已成功，不处理直接返回结果");
            wechatPayResultNoticeResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            wechatPayResultNoticeResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            bizResponse.setResult(wechatPayResultNoticeResponse);
            bizResponse.setRspSysId(AppParamConstant.IGAS);
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            return bizResponse;
        }

        /* 支付成功,更新当前支付订单状态 */
        userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
        userOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
        userOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
        userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
            mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            mchntOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
            mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        }
        /* 处理付款方账户类型 */
        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(payOrderInfo.getInstId(), "WCHAT_CARDTYPE", wechatPayResultNoticeRequest.getBankType());
        if (wechatPayResultNoticeRequest.getBankType().contains("DEBIT")) {
            payOrderInfo.setPayerAcctType((null == sysParam) ? AcctTypeEnum.OTHER_DEBIT.getAcctType() : AcctTypeEnum.BANK_DEBIT.getAcctType());
        } else if (wechatPayResultNoticeRequest.getBankType().contains("CREDIT")) {
            payOrderInfo.setPayerAcctType((null == sysParam) ? AcctTypeEnum.OTHER_CREDIT.getAcctType() : AcctTypeEnum.BANK_CREDIT.getAcctType());
        }
        /* 付款信息 */
        payOrderInfo.setPayerAcctInfo("微信用户");
        rglog.info("付款账户类型<{}>", payOrderInfo.getPayerAcctType());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
        payOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
        payOrderInfo.setSettleDate(DateUtil.getCurrentDate());
        payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        /* 保存相应信息和相应码 */
        payOrderInfo.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        payOrderInfo.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        /*判断是否有商户在微信侧的营销,商户出资优惠金额=订单金额-商户实收金额*/
        if (!StringUtil.isEmptyOrNull(wechatPayResultNoticeRequest.getOrderAmt()) &&
                !StringUtil.isEmptyOrNull(wechatPayResultNoticeRequest.getSettleAmt())
                && AmountUtil.compare(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt()) > 0) {
            /* 支付宝订单金额=用户实际支付金额>支付宝商户清算金额，存在支付宝营销 */
            rglog.debug("存在商户侧，在微信侧出资优惠金额<{}>", AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt()));
            /* 处理营销金额,更新用户优惠金额累计，实际优惠金额=实际优惠金额+支付宝优惠金额 */
            userOrderInfo.setRealDiscountAmt(AmountUtil.addition(userOrderInfo.getRealDiscountAmt(),
                    AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt())));
            /* 用户订单表的实际支付金额=用户订单表的实际支付金额-支付宝优惠金额 */
            userOrderInfo.setRealPayAmt(AmountUtil.subtraction(userOrderInfo.getRealPayAmt(),
                    AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt())));
            /* 处理商户清算金额 商户订单表中实际清算金额=实际清算金额-支付宝优惠金额 */
            if (mchntOrderInfoList.size() > 1) {
                String remainAmt = "0.00";
                /*总优惠金额*/
                String merDiscAmt = AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt());
                /* 计算每个商户平均的优惠 */
                String merPerDiscAmt = AmountUtil.division(merDiscAmt, String.valueOf(mchntOrderInfoList.size()), 2);
                /* 判断营销金额是否能完全平均 */
                if (AmountUtil.compare(merDiscAmt, AmountUtil.multiplication(merPerDiscAmt, String.valueOf(mchntOrderInfoList.size()))) != 0) {
                    /* 剩余金额 */
                    remainAmt = AmountUtil.subtraction(merDiscAmt, AmountUtil.multiplication(merPerDiscAmt, String.valueOf(mchntOrderInfoList.size())));
                }
                for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                    mchntOrderInfo.setRealSettleAmt(AmountUtil.subtraction(mchntOrderInfo.getRealSettleAmt(), merPerDiscAmt));
                }
                /* 把剩余优惠金额用到商户定列表中，最后一笔中 */
                String lastMchntRealSettleAmt = AmountUtil.subtraction(mchntOrderInfoList.get(mchntOrderInfoList.size() - 1).getRealSettleAmt(), remainAmt);
                mchntOrderInfoList.get(mchntOrderInfoList.size() - 1).setRealSettleAmt(lastMchntRealSettleAmt);
            } else {
                mchntOrderInfoList.get(0).setRealSettleAmt(AmountUtil.subtraction(mchntOrderInfoList.get(0).getRealSettleAmt(),
                        AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt())));
            }
            /* 存储通道优惠金额 */
            payOrderInfo.setChannelDiscountAmt(AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt()));
            /* 支付订单表的实际支付金额=支付订单表的实际支付金额-支付宝优惠金额 */
            payOrderInfo.setRealPayAmt(AmountUtil.subtraction(payOrderInfo.getRealPayAmt(),
                    AmountUtil.subtraction(wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt())));
        } else {
            /* 默认支付侧无商户营销，金额做处理 */
            rglog.debug("微信订单金额:<{}>,微信商户打款金额:<{}>", wechatPayResultNoticeRequest.getOrderAmt(), wechatPayResultNoticeRequest.getSettleAmt());
        }

        /* 计算商户手续费 */
        GlobalTransUtil.setCacheValue(TransCacheConstant.MCHNT_ORDER_INFO_LIST, mchntOrderInfoList);
        MchntService mchntService = new MchntServiceImpl();
        boolean calcResult = mchntService.calcMchntFee(mchntOrderInfoList, FeeTypeEnum.WECHAT.getFeeType());
        if (!calcResult) {
            rglog.debug("商户手续费计算失败，只更新订单状态！");
            orderService.updateOrderInfo(userOrderInfo, mchntOrderInfoList, payOrderInfo);
        } else {
            /* 计算商户优惠手续费以、虚拟账户记账以及交易通知等 */
            if (null == txnInfo.getChannelCallCfgList() || txnInfo.getChannelCallCfgList().isEmpty()) {
                rglog.error("<{}-{}>交易未配置交易通道服务调用配置信息！", txnInfo.getSrcTxnAuthCfg().getTxnNum(), txnInfo.getSrcTxnAuthCfg().getTxnName());
                throw new BizException(RespCodeEnum.TRANS_NOT_SUPPORT.getRespCode(), RespCodeEnum.TRANS_NOT_SUPPORT.getRespDesc());
            }
            List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item ->
                    item.getCallIndex().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX)).collect(Collectors.toList());
            ChannelCallCfg channelCallCfg = channelCallSceneDiscern(wechatPayResultNoticeRequest, channelCallCfgList);
            Class channelClasz = Class.forName(channelCallCfg.getCallChannelImpl());
            ChannelBaseService channelBaseService = (ChannelBaseService) channelClasz.newInstance();
            channelBaseService.callService(txnInfo, orderInfo, channelCallCfg.getBizScene(), request);
        }

        /* 更新商户累计限额 */
        mchntService.updateMchntTransLimit(mchntOrderInfoList);

        /* 组装应答报文 */
        wechatPayResultNoticeResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        wechatPayResultNoticeResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setResult(wechatPayResultNoticeResponse);
        bizResponse.setRspSysId(AppParamConstant.IGAS);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        WechatPayResultNoticeResponse wechatPayResultNoticeResponse = (WechatPayResultNoticeResponse) bizResponse.getResult();
        ConvertUtil.convertInput(wechatPayResultNoticeResponse);
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        Optional<ChannelCallCfg> channelCallCfgOpt;
        if ("0101".equals(channelCallCfgList.get(0).getCallIndex())) {
            List<MchntOrderInfo> mchntOrderInfoList = (List<MchntOrderInfo>) GlobalTransUtil.getCacheValue(TransCacheConstant.MCHNT_ORDER_INFO_LIST);
            if ("00".equals(Objects.requireNonNull(mchntOrderInfoList).get(0).getBizSceneType()) || "01".equals(mchntOrderInfoList.get(0).getBizSceneType())
                    || "02".equals(mchntOrderInfoList.get(0).getBizSceneType()) || "0".equals(mchntOrderInfoList.get(0).getFeeInputMode())) {
                /* 担保支付、购买卡卷、特殊计算商户不给商户进行实时入账及虚拟账记账，只推送交易结果通知 */
                rglog.info("订单全为购买卡券或担保支付或特殊计费商户的交易，不给商户入账，直接推送通知");
                channelCallCfgOpt = channelCallCfgList.stream().filter(item -> item.getCallChannelId().equals("LOCAL")).findFirst();
            } else {
                if (AppParamConstant.YES.equals(Objects.requireNonNull(mchntOrderInfoList).get(0).getRealSettleFlag())) {
                    /* 商户D0清算场景 */
                    channelCallCfgOpt = channelCallCfgList.stream().filter(item -> item.getCallChannelId().equals(ChannelEnum.ESB.getChannelType())).findFirst();
                } else {
                    /* 商户非D0清算场景 */
                    channelCallCfgOpt = channelCallCfgList.stream().filter(item -> item.getCallChannelId().equals(ChannelEnum.ACCT.getChannelType())).findFirst();
                }
            }
            return channelCallCfgOpt.orElse(null);
        } else {
            channelCallCfgOpt = channelCallCfgList.stream().filter(item -> item.getBizScene().equals("00")).findFirst();
        }
        return channelCallCfgOpt.orElse(null);
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        return CheckResultEnum.PASSED;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        return transStatusEnum;
    }
}
